/*->c.tek */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"
#include "h.flex"

#include "h.def"

#include "h.DrawLevel0"

#include "h.BezierArc"

#include "h.wos"
#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.pr"

#include "h.term"

#include "h.vtdef"
#include "h.vtwimp"

#include "h.tekint"
#include "h.tek"



/*****************************************************************************/
/* Tektronix terminal external variables */

tekcstr tekc;                      /* cursor position */


int     tekbypassmode;             /* bypass mode ?    */
int     tekmode;                   /* tek mode         */


int     tekbypasschar;             /* bypass character     */
int     tekignoredels;             /* ignore deletes state */

int     tekmacrosenabled;          /* keyboard macros enabled ? */



int     teklinestyle;              /* current tek line style */
int     teklineindex=1;            /* colour index for lines */

int     tekfillindex=1;            /* -ve colour index +ve pattern */

int     tekbackindex=0;            /* index for background */

int     tekfont;                   /* current tek font - an indedx to the 
                                      alpha text size to use on the graphics
                                      plane */

int     tekfontsize=61;            /* size of graph text */

int     tekfontindex=1;            /* graph text colour */


int     tekmarker;                 /* marker number */


int     tekipen;                   /* 0/1, plot points in point plot mode */


tekcstr tekgin;                    /* coords for GIN cursor to appear at */
int     tekgstepn=5;               /* coords step for gin cursor */
int     tekgsteps=10;              /* coords step for gin cursor with SHIFT */


int     tektextplane=1;            /* is the text plane enabled ? */
int     teknew;                    /* has the text plane ever been opened ? */


int     tekdefindex[TEKNINDEX]=    /* RGB values for each index */
        {
         0x00000000,               /* 0 Black */
         0xFFFFFF00,               /* 1 White */
         0x0000FF00,               /* 2 Red   */
         0x00FF0000,               /* 3 Green */
         0xFF000000,               /* 4 Blue  */
         0xFFFF0000,               /* 5 Cyan (blue+green) */
         0xFF00FF00,               /* 6 Magnta (red+blue) */
         0x00FFFF00,               /* 7 Yellow (red+green) */
         0x00BBFF00,               /* 8 Orange */
         0x00FFBB00,               /* 9 Green Yellow */
         0xBBFF0000,               /* 10 Green Cyan */
         0xFFBB0000,               /* 11 Blue Cyan */
         0xFF00BB00,               /* 12 Blue Magenta */
         0xBB00FF00,               /* 13 Red Magenta */
         0x77777700,               /* 14 Dark Grey */
         0xDDDDDD00                /* 15 Light Grey */
        };


int     tekindex[TEKNINDEX];



char tekeolstring[TEKSTRLEN1];
int  tekeolstringlen;

char tekeofstring[TEKSTRLEN1];
int  tekeofstringlen;

char tekpromptstring[TEKSTRLEN1];
int  tekpromptstringlen;


int  tekfirsteom=13;               /* first end of message indicator  */
int  teksecondeom=0;               /* second end of message indicator */

int  tekdefcolourmode=TEKHLS;      /* HLS etc. */

int  tekversion=4105;


/*****************************************************************************/
/* Tektronix terminal internal variables */

int  tekesc;
int  tekstate;
int  tekfirst;
int  teksecond;
int  tekparam;
int  tekparams;

int  tekaccseq;              /* used for accumulating position */
int  tekaccbits;

int  tekstrp;                /* used for accumulating strings */
char tekstr[TEKSTRSIZE];
int  tekstrlen;              /* length */

int  tekbyte;                /* single byte parameter */



char echostring[10];         /* used by echoplex mode          */
int  echopoi;

tekcstr tekmov;
tekcstr tekold;


int     tekdx;               /* x and y size of fonts on graphics plane */
int     tekdy;               
                             

int     tekpanel;            /* a panel is being defined */
int     tekpanelx;           /* coors of start of panel  */
int     tekpanely;
int     tekpanelboundary;    /* fill over boundary       */
int     tekpaneloffset;

int     tekbakpal;           /* RGB values for background */


/*****************************************************************************/
/* Tektronix terminal user options */

int    tek4010;                /* switch on unspecified 4010 features */
int    teklockcols;            /* lock colours */
int    tekmargins=1;           /* show printer margins */

zoomer tekzoom={1,1,0};        /* zoom for window */

int    tekinvert;              /* save inverted */

int    tekdumptype;            /* sort of graphics dump 0==-ve 1==+ve */


/*****************************************************************************/
/* Tektronix terminal wimp variables */


int       tekopen;                   /* tek window open ? */
int       tekexists;


int       tekupdate;                 /* flag changes to screen contents */
int       tekcurstime;               /* time to change cursor at */

int       tekdrag;

Draw_diag tekdiag;
Draw_diag teklast;


/*****************************************************************************/


/* reset tek variables */

void tekstart(void)
{
 tekc.x=0;
 tekc.y=TEKVISH-tekdy;
 tekmode='A';
 tekc.curs=TEKVCURS;
 tekesc=0;
 tekaccseq=0;
 tekstate=TEKC1;
 tekbypassmode=0;
 tekpanel=0;
 tekmov.x=tekmov.y=-1;
}




/* convert from tek pt to os units */

int tekos(int tekpt)
{
 if(tekzoom.mul==tekzoom.div) return((tekpt*9)>>(2+3));
 else                         return((tekpt*tekzoom.mul*9)/(tekzoom.div*4*8));
}



/* convert from os to tek pt */

int ostek(int osunits)
{
 if(tekzoom.mul==tekzoom.div) return((osunits<<(2+3))/9);
 else                        return((osunits*tekzoom.div*4*8)/(tekzoom.mul*9));
}



/* tek pt to os units - independent of zoom */

int tekeos(int tekpt)
{
 if(tekzoom.var) return((tekpt*9)>>(2+3));
 else            return(tekos(tekpt));
}



/* convert from tek pt to Draw units */

int tekdrw(int tekpt)
{
 return(tekpt*9*64/8);
}


/* convert from tek pt to internal units */

int tekint(int tekpt)
{
 return((tekpt*8*400*9)>>8);

/* return((tekpt*64*400*9/8)>>8); */
}



int osunits(int ourunits)
{
 if(tekzoom.mul==tekzoom.div) return(ourunits/400);
 else                         return((ourunits*tekzoom.mul)/(tekzoom.div*400));
}



/* save cursor position */

void teksaveold(void)
{
 tekold=tekc;
}


/*****************************************************************************/

#define TEKFLUSHSIZE 0x100

/* merges the contents of the teklast diag with tekdiag */

void tekflush(void)
{
 closediag(&teklast);
 mergediag(&teklast,&tekdiag);
 opendiag(&teklast,tekdrw(TEKW),tekdrw(TEKVISH));

}


/* looks at tek last, and if needed calls tekflush */

void tekcheck(void)
{
 if(itemsdiag(&teklast)>2) 
 {
  compactdiag(&teklast,&tekdiag);
 /* if(tekpaneloffset)  tekpaneloffset=64; */

  if(tekpaneloffset)
  {
   tekpaneloffset=drawheadersize;
  }
 }
 else
 if(!tekpanel && teklast.length>TEKFLUSHSIZE) tekflush();
}



int tekdxdata[4]={55,50,33,30};
int tekdydata[4]={89,82,53,48};


void teksetfontsize(int font)
{
 tekdx=tekdxdata[font];
 tekdy=tekdydata[font];
}


void tekchar(int x,int y,int c)
{
 vectextcolour(tekindex[tekfontindex],tekbakpal,&teklast);
 vectextsize(tekdrw(tekdx),tekdrw(tekdy),&teklast);
 vecsym(tekdrw(x),tekdrw(y),c,&teklast);
 tekupdate=1;
}


void tekstring(int x,int y,char * string)
{
 int len=strlen(string);
 int i;

 vectextcolour(tekindex[tekfontindex],tekbakpal,&teklast);
 vectextsize(tekdrw(tekfontsize),tekdrw(tekfontsize),&teklast);

 i=0;
 while(len--)
 {
  if(string[i]>SPC) vecsym(tekdrw(x),tekdrw(y),string[i],&teklast);
  x+=tekfontsize;
  i++;
 }
 tekupdate=1;
}


void tekmove(int x,int y)
{
 veclinecolour(tekindex[teklineindex],&teklast);
 if(tekpanel && !tekpaneloffset) tekpaneloffset=teklast.length;
 vecmove(tekdrw(x),tekdrw(y),&teklast);
 tekupdate=1;
}


void tekdraw(int x,int y)
{
 vecdraw(tekdrw(x),tekdrw(y),&teklast);
 tekupdate=1;
}




void tekcircle(int x,int y,int radius)
{
 bezier_arc_coord centre;
 bezier_arc_coord path[13];
 int              i;

 centre.x=tekdrw(x);
 centre.y=tekdrw(y);

 bezier_arc_circle(centre,tekdrw(radius),path);

 vecmove(path[0].x,path[0].y,&teklast);
 for(i=1;i<13;i+=3)
  veccurve(path[i].x,path[i].y,path[i+1].x,path[i+1].y,
                                   path[i+2].x,path[i+2].y,&teklast);
 tekupdate=1;
}




/* complete panel */

void tekendpanel(void)
{
 vecfillcolour(tekindex[tekfillindex],&teklast,tekpaneloffset);
 closediag(&teklast);
}



/* start panel */
/* (1) complete anything that is being drawn */
/* (2) block any further compaction          */
/* (3) set a pointer to the filled object    */


void tekstartpanel(void)
{
 closediag(&teklast);
 tekpaneloffset=0;
}



/* Draw current marker */

void tekplot(int x,int y)
{
 tekchar(x-tekdx/2,y-tekdy/2,0x80+tekmarker);
}





void teksetlinestyle(int style)
{
 if(style<0) style=0;
 if(style>7) style=7;

 teklinestyle=style;
 veclinestyle(style,&teklast);
}




void tekdump(int invert)
{
 if(printer) tekprintfile(invert);
}



void tekclglo(void)
{
 opendiag(&tekdiag,tekdrw(TEKW),tekdrw(TEKVISH));
 opendiag(&teklast,tekdrw(TEKW),tekdrw(TEKVISH));
 vectextsize(tekdrw(tekdx),tekdrw(tekdy),&teklast);
 tekupdate=0;
 teksaveold();
 tekbakpal=tekindex[tekbackindex];
}


void tekclg(void)
{
 tekclglo();
 refreshwindow(whandle[TEK]);
}



void tekrefreshbackground(void)
{
 tekbakpal=tekindex[tekbackindex];
 refreshwindow(whandle[TEK]);
}


/*****************************************************************************/


void tekzero(void)
{
 if(tekcurstime<zerotime)
 {
  if(tekmode=='A')
  {
   if(tekc.curs==TEKVCURS) tekc.curs=TEKNOCURS;
   else                    tekc.curs=TEKVCURS;
  }
  tekcurstime=zerotime+50;
 }

 if(tekmode=='A' && tekc.curs==TEKGINCURS && tektextplane) vtsetfocus();
 else
 if(tekmode=='G' && tekc.curs!=TEKGINCURS) teksetfocus();

 if(tekdrag)
 {
  getpointer();
  if(buttons)
  {
   getw(whandle[TEK]);
   tekc.x=ostek(mousex-bx);
   tekc.y=TEKVISH-ostek(by-mousey);

   if(tekc.x<0)       tekc.x=0;
   if(tekc.x>TEKW)    tekc.x=TEKW;
   if(tekc.y<0)       tekc.y=0;
   if(tekc.y>TEKVISH) tekc.y=TEKVISH;
  }
  else tekdrag=0;
 }

 if(tekupdate)
 {
  if(tekmode=='A')
  {
   tekc.curs=TEKVCURS;
  }
  validdiag(&teklast);
  tekupdatewindow(&tekold,&tekc);
  tekupdate=0;
  teksaveold();
  tekcheck();
 }
 else
 if(tekold.x!=tekc.x || tekold.y!=tekc.y || tekold.curs!=tekc.curs)
 {
  if(tekmode=='A' && (tekold.x!=tekc.x || tekold.y!=tekc.y))
                                                         tekc.curs=TEKVCURS;
  tekupdatecursor(&tekold,&tekc);
  teksaveold();
 }
}




/* used only from clicks on Tek window or open tek fn */

void teksetfocus(void)
{
 if(tekmode=='G' || !tektextplane) setfocus(whandle[TEK]);
 if(terminalmodeset) terminalmode=TMODEVT;
}



/* used only from VT to go into Tek mode */

void teksetfocusfront(void)
{
 if(tektextplane) vtentertekmode();
 teksetfocus();
 if(tekmode=='G' || !tektextplane) forward(whandle[TEK]);
}




/* enable/disable tek alpha plane */

void tekdoenabletextplane(int enable)
{
 tektextplane=enable;

 if(enable)
 {
  vtopenwindows(teknew);
  teknew=0;
  vtsetfocus();
  if(vttekmode) vtentertekmode();
 }
 else
 {
  vtclosewindows();
  vtquittekmode();
  teksetfocus();
 }
}




void tekdefcolours(void)
{
 int i;
 for(i=0;i<TEKNINDEX;i++) tekindex[i]=tekdefindex[i];
}



/* converts hls to rgb */


/* hue range 0 to 360  */
/* lightness 0 to 100  */
/* saturation 0 to 100 */


void hlstorgb(int * h,int * l,int * s)
{
 int r;
 int g;
 int b;
 int mincol;
 int maxcol;
 int hue=*h;
 int light=*l;
 int sat=*s;

 if(sat<0)   sat=0;
 if(sat>100) sat=100;

 if(light<0)   light=0;
 if(light>100) light=100;

 if(hue<0)     hue=0;
 if(hue>360)   hue=360;


 if(light==0) maxcol=mincol=0;
 else
 if(sat==0)   maxcol=mincol=light;
 else
 if(light<=50)
 {
  maxcol=light*(1+(100/sat));
  mincol=light*(1-(100/sat));
 }
 else
 {
  maxcol=(sat*(100-light))/100+light;
  mincol=light-(sat*(100-light))/100;
 }


 if(hue<=120)
 {
  g=mincol;
  if(hue<=60)
  {
   b=maxcol;
   r=mincol+hue*(maxcol-mincol)/(120-hue);
  }
  else
  {
   r=maxcol;
   b=mincol+(120-hue)*(maxcol-mincol)/hue;
  }
 }
 else
 if(hue<=240)
 {
  b=mincol;
  if(hue<=180)
  {
   r=maxcol;
   g=mincol+(hue-120)*(maxcol-mincol)/(240-hue);
  }
  else
  {
   g=maxcol;
   r=mincol+(240-hue)*(maxcol-mincol)/(hue-120);
  }

 }
 else
 {
  r=mincol;

  if(hue<=300)
  {
   g=maxcol;
   b=mincol+(hue-240)*(maxcol-mincol)/(360-hue);
  }
  else
  {
   b=maxcol;
   g=mincol+(360-hue)*(maxcol-mincol)/(hue-240);
  }
 }

 *h=r;
 *l=g;
 *s=b;
}


/* index, is first index to define, then RGB etc. */
/* mode is HLS etc. */

void tekdefineindex(int index[],int mode)
{
 int i=index[0];
 int j;

 if(teklockcols) return;
 if(i<0 || i>=TEKNINDEX) return;

/* dprintf(0,"index=%d mode=%d r=%d g=%d b=%d",
   index[0],mode,index[1],index[2],index[3]);   */


 if(mode==TEKCMY) for(j=1;j<4;j++) index[j]=100-index[j];
 else
 if(mode==TEKHLS)
 {
  index[1]=index[1] % 360;
  hlstorgb(&index[1],&index[2],&index[3]);
 }

 for(j=1;j<4;j++)
 {
  if(index[j]<0)   index[j]=0;
  if(index[j]>100) index[j]=100;

  index[j]=(index[j]*255)/100;
 }

 tekindex[i]=(index[1]<<8)+(index[2]<<16)+(index[3]<<24);
}


/*****************************************************************************/



void tekclosewindows(void)
{
 if(tekopen)
 {
  remzeroevent(TEKZERO);
  wimp_close_wind(whandle[TEK]);
  tekopen=0;
 }
}




void tekdestroy(void)
{
 if(tekexists)
 {
  closedownt(TEK);
  tekdrawfinish();
  tekexists=0;
 }
}


void tekcreate(void)
{
 int handle;

 if(tekexists) return;

 handle=createwindow(TEK);

 /* tekzoom.mul=tekzoom.div=1; */

 extent(handle,0,-tekeos(TEKVISH),tekeos(TEKW),0);

 tekdrawinit();
 tekdefcolours();

 teksetfontsize(0);
 teksetlinestyle(0);

 tekstart();
 tekclglo();
 teknew=1;
 tekexists=1;
}





void tekopenwindows(int new)
{
 int handle=whandle[TEK];
 wimp_wstate winds;

 tekopen=1;
 tekdrag=0;

 wimp_get_wind_state(handle,&winds);

 if(new)
 {
  winds.o.box.x0=0;
  winds.o.box.x1=screenx-vscrlbar;
  winds.o.box.y1=screeny-hscrlbar;
  winds.o.box.y0=winds.o.box.y1-tekeos(TEKVISH);
  winds.o.behind=-1;
  clipwindow(&winds.o,1);
 }

 wimp_open_wind(&winds.o);

 addzeroevent(TEKZERO);

 if(!tektextplane)
 {
  setfocus(whandle[TEK]);
  if(terminalmodeset) terminalmode=TMODEVT;
 }
}




/*****************************************************************************/



void teknewzoom(int mul,int div)
{
 if(tekzoom.mul*div!=tekzoom.div*mul)
 {
  tekzoom.mul=mul;
  tekzoom.div=div;
  refreshwindow(whandle[TEK]);
 }
}


void tekvarzoomlo(void)
{
 int xmul;
 int xdiv;
 int ymul;
 int ydiv;


 getw(whandle[TEK]);

 xdiv=tekeos(TEKW)>>4;
 ydiv=tekeos(TEKVISH)>>4;
 xmul=(x1-x0)>>4;
 ymul=(y1-y0)>>4;

 if(xmul>xdiv) xmul=xdiv;
 if(ymul>ydiv) ymul=ydiv;

 /* problem is that wimp will round up window extent to next biggest pixel */
 /* so xmul can be bigger than the extent xdiv */


 if(xmul*ydiv>ymul*xdiv) teknewzoom(xmul,xdiv);
 else                    teknewzoom(ymul,ydiv);
}


void wopentek(void)
{
 clipwindow(&(wimpevent.data.o),1);
 wimp_open_wind(&(wimpevent.data.o));
 if(tekzoom.var) tekvarzoomlo();
}



int savetekpic(char * filename)
{
 /* tekflush(); */

 if(tekinvert)
 {
  invertdiag(&tekdiag);
  invertdiag(&teklast);
 }

 drawsavediag(filename,&tekdiag,&teklast);

 if(tekinvert)
 {
  invertdiag(&tekdiag);
  invertdiag(&teklast);
 }

 return(1);
}




void tekclick(void)
{
 if(buttons==2) poptekmain();
 else
 if(buttons==4 || buttons==0x40)
 {
  findcaret();
  if(chandle!=whandle[TEK]) teksetfocus();
  else
  if(tekmode=='G' && buttons==4) tekdrag=1;
 }
}




void tekdoreset(void)
{
 tekstart();
 tekclg();
}




void teksetindex(int * index,int value)
{
 if(!teklockcols)
 {
  if(value<0) value=0;
  if(value>=TEKNINDEX) value=TEKNINDEX-1;
  *index=value;
 }
}



void tekgetcurs(int * x,int * y)
{
 *x=tekc.x;
 *y=tekc.y;
}


void teksetcurs(int x,int y)
{
 tekc.x=x;
 tekc.y=y;
}


void tekinit(void)
{
 tekdefcolours();


}



